package semantic_compute.entity_linking.yago_linker;

import com.ambiverse.api.AmbiverseApiClient;
import com.ambiverse.api.model.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import common.helper.json.JavaToJsonString;
import common.helper.json.JsonToJavaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import semantic_compute.common.yago_helper.YagoLuceneQueryer;
import semantic_compute.common.yago_helper.YagoWikipediaMap;
import semantic_compute.entity_linking.schema.EntityLinkingResult;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by julianzliu on 4/22/2017.
 */
public class YagoQueryEntityLinker {

    static final Logger logger = LoggerFactory.getLogger(YagoQueryEntityLinker.class);
    private static final String LF = System.lineSeparator();

    /** Global instance of the JSON factory. */
    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();

    /** Global instance of the HTTP transport. */
    private static HttpTransport httpTransport = new NetHttpTransport();

    private static final NumberFormat numberFormat = NumberFormat.getIntegerInstance();

    private AmbiverseApiClient client = null;

    private YagoWikipediaMap yagoWikipediaMapper = null;


    public YagoQueryEntityLinker() {
        try{
            Credential credential = AmbiverseApiClient.authorize(httpTransport, JSON_FACTORY);
            logger.info("Successfully obtained OAuth 2 access token." + LF);
            // Instantiate a new API client
            this.client = new AmbiverseApiClient(httpTransport, JSON_FACTORY, credential);

            this.yagoWikipediaMapper = new YagoWikipediaMap();
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public JsonNode getYagoEntityLinkingJson(String text){
        String json_result = "";
        try{
            AnalyzeInput input = new AnalyzeInput()
                    .withLanguage("en")		// Optional. If not set, language detection happens automatically.
                    .withText(text);
            System.out.println("Sent text to /entitylinking/analyze for analysis: \"" + text + "\"");

            AnalyzeOutput output = client.entityLinking().analyze().process(input).execute();

            System.out.println("Recognized entities:");

            json_result = JavaToJsonString.mapJavaToJson(output);

            System.out.println("[JSON RESULT:]\n" + json_result);

            //EntityReference entityReference = new EntityReference();
            //entityReference.

            /*
            for (Match match : output.getMatches()) {
                System.out.println("- Text match: " + match.getText() +
                        " (" + match.getCharOffset() +
                        ", " +
                        (match.getCharOffset() + match.getCharLength()) +
                        ") ");
                System.out.println("  Linked entity: " + match.getEntity().getId() +
                        " (confidence score: " + match.getEntity().getConfidence() + ")");
            }
            */



            /*
            // Entity Linking Service - Request metadata from the Entity Linking endpoint
            System.out.println("Querying metadata at the /entitylinking/analyze/_meta endpoint.");
            Meta m = client.entityLinking().analyze().getMeta().execute();
            System.out.println("- dump version: " + m.getDumpVersion());
            System.out.println("- supported languages: " + m.getLanguages());
            System.out.println("- database creation date: " + m.getCreationDate());
            System.out.println(LF);
            */


        }catch (Exception e){
            e.printStackTrace();
        }

        JsonNode result = JsonToJavaObject.loadJsonNode( json_result );
        return result;
    }

    public EntityLinkingResult getYagoEntityLinkingResult(String text){
        JsonNode result = getYagoEntityLinkingJson( text );
        //String petty_reuslt = JsonToJavaObject.jsonNodeToString(result);
        //System.out.println( petty_reuslt );
        EntityLinkingResult linkingResult = parseEntityLinkingResult(result, text);
        //System.out.println("[getYagoEntityLinkingResult] parseEntityLinkingResult Finished!");

        try {
            /*
            TODO :
             */
            //linkingResult.extractLinkedEntities();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }


        return linkingResult;
    }

    public EntityLinkingResult parseEntityLinkingResult(JsonNode result, String text){
        EntityLinkingResult linkingResult = new EntityLinkingResult();
        linkingResult.originalText = text;
        linkingResult.annotatedText = null;


        // metas
        Map<String,EntityLinkingResult.EntityMetadata> entityMetadataMap = new HashMap<>();
        //JsonNode entityMetadatas = result.get("entityMetadata");


        // mentions
        System.out.println("[parseEntityLinkingResult] begin parse mentions");
        List<EntityLinkingResult.LinkedEntity> entities = new ArrayList<>();
        ArrayNode mentions = (ArrayNode)result.get("matches");
        for(JsonNode mention:mentions) {
            EntityLinkingResult.LinkedEntity entity = new EntityLinkingResult.LinkedEntity();

            entity.name = mention.get("text").asText();
            entity.offset = mention.get("charOffset").asInt();
            entity.length = mention.get("charLength").asInt();
            entity.score = mention.get("entity").get("confidence").asDouble();

            entity.entity = mention.get("entity").get("id").asText();

            entities.add(entity);

            EntityLinkingResult.EntityMetadata metadata;
            if (entityMetadataMap.containsKey(entity.entity)) {
                metadata = entityMetadataMap.get(entity.entity);
            } else {
                metadata = new EntityLinkingResult.EntityMetadata();
                entityMetadataMap.put(entity.entity, metadata);
                metadata.url = mention.get("entity").get("url").asText();
                metadata.importance = mention.get("entity").get("confidence").asDouble();
                metadata.entityId = entity.entity;
                metadata.WIKIDATA_ID = entity.entity;
                String YAGO_ID = this.yagoWikipediaMapper.mapWikipediaURLtoYagoID( metadata.url );
                metadata.YAGO_ID = YAGO_ID;
                //if(YAGO_ID!=null) metadata.entityId
                metadata.knowledgebase = "WIKIDATA";
            }
        }
        linkingResult.mentions = entities;
        linkingResult.entityMetadata = entityMetadataMap;

        return linkingResult;
    }


    /*********************************************************
     *
     */
    public static void main(String[] args){
        YagoQueryEntityLinker entityLinker = new YagoQueryEntityLinker();

        /*
        注意，加句号能识别
        否则不能识别。
        查询处理时，加上句号！！！！！
         */
        String text = "Obama was born in Hawaii.";

        //entityLinker.getYagoEntityLinkingJson( text );

        EntityLinkingResult result = entityLinker.getYagoEntityLinkingResult( text );
        result.alignWithCoreNlp();

        System.out.println("\n\n\n\n--------------------------------");
        System.out.println(result.toString());


    }


}
